﻿/**
 * @file ascii.c
 * @brief this is a brief description
 * @details  针对ascii模式对adu进行封装
 * @author fulong 
 * @data 7/4/2014
 * @version 1.0
 * @par Copyright (c):
 * @par First build
 *     version: fulong 
 *     data: 7/4/2014
 */
#include "ascii.h"
#include "../../../lib/lrc.h"
#include "../../../dev/uart.h"
#include "../../../dev/485.h"
#include "../../../lib/libmath.h"
#include "../../../lib/delay.h"
#include "../../../hal/hal_uart.h"
#include "../ms_protocol/common.h"
#include "../mb_time_manage/mb_time.h"

#ifdef MODBUS_ENABLE

#define ASCII_STOP 0
#define ASCII_START 1

#ifdef MODBUS_ASCII_MODE
#define FRAME_SYMBOL_LEN 3

#define ASCII_EXCEPT_ADU_MAX_LEN (RESPOND_ADU_LEST_LEN+1)

#define ascii_bus_init()  {ascii_receive_status=ASCII_STOP; slave_receiving_counter = 0;}
#define ascii_bus_start_receive() { ascii_receive_status=ASCII_START; slave_receiving_counter = 0; }

typedef enum {
    SLAVE_ADDRESS_OFFSET = 0,
    FUNCTION_CODE_OFFSET = 2,
    DATA_OFFSET = 4
}ADU_offect;


static uint8 ascii_receive_status;


extern mb_status_struct slave_mb_status;
extern receive_frame_struct slave_receive_frame;
extern uint8 slave_receiving_counter;

void ascii_mode_init(void) {
    mb_time_manage_init();
    mb_frame_char_timeout_clr();
    slave_mb_status.mb_status = 0;
    slave_mb_status.data_process_done = 0;
    ascii_receive_status = 0;
}
/*! \brief ascii模式下的接收处理函数,通过这个函数,将接收到的ascii码转换成对应十六进制数据结构分类保存处理.
 * \param
 * \retrun
 */
void ascii_receive(void) {
    uint8 num[ 3 ] = { 0, 0, 0 };
    uint8 data_len, verifaction_offset;
    /*只有在数据处理结构没被占用的时候,才会进入这个函数*/
    if (slave_mb_status.data_process_done == 0) {
        num[0] = slave_receive_frame.receive_frame[SLAVE_ADDRESS_OFFSET];
        num[1] = slave_receive_frame.receive_frame[SLAVE_ADDRESS_OFFSET + 1];
        slave_mb_status.mb_adu->addr = hexchar2num(num);
        num[0] = slave_receive_frame.receive_frame[FUNCTION_CODE_OFFSET];
        num[1] = slave_receive_frame.receive_frame[FUNCTION_CODE_OFFSET + 1];
        slave_mb_status.mb_adu->mb_req_pdu.function_code = hexchar2num(num);
        slave_mb_status.mb_adu->mb_req_pdu.request_data_len = slave_mb_status.mb_frame_len - 3 * 2;
        for (data_len = 0; data_len <  slave_mb_status.mb_adu->mb_req_pdu.request_data_len; data_len += 2) {

            num[0] = slave_receive_frame.receive_frame[DATA_OFFSET + data_len];
            num[1] = slave_receive_frame.receive_frame[DATA_OFFSET + data_len + 1];
            slave_mb_status.mb_adu->mb_req_pdu.request_data[data_len >> 1] = hexchar2num(num);
        }
        /*接收的数据都是十六位字符表示八位字符的,转换成二进制后,就变成八位数字了*/
        slave_mb_status.mb_adu->mb_req_pdu.request_data_len /= 2;
        verifaction_offset = data_len;
        num[0] = slave_receive_frame.receive_frame[verifaction_offset + DATA_OFFSET];
        num[1] = slave_receive_frame.receive_frame[verifaction_offset + DATA_OFFSET + 1];
        slave_mb_status.mb_adu->verifaction_low8 = hexchar2num(num);
        slave_mb_status.mb_adu->verifaction_high8 = 0;
        slave_mb_status.data_process_done = 1;
    }
}
void ascii_send(void) {
    send_byte('S');
}
/*! \brief ascii模式下的校验函数
 * \param mb_adu 需要校验的mb_adu单元数据
 * \retrun VERIFY_SUCCESS 表示mb_adu的数据接收正常,modbus会进行下一个状态的处理
 * \retrun VERIFY_FAIL 表示mb_adu的数据接收有误,modbus会被初始化并退回空闲状态.
 */
uint8 ascii_adjust_verify(mb_adu_struct *mb_adu) {
    uint8 verify;
    uint8 data_len;
    /*生成验证数组*/
    uint8 verify_array[ RECEIVE_MAX_LEN + 1 + 2 ];
    verify_array[0] = mb_adu->addr;
    verify_array[1] = mb_adu->mb_req_pdu.function_code;
    for (data_len = 0; data_len <  mb_adu->mb_req_pdu.request_data_len; data_len++) {

        verify_array[2 + data_len] = mb_adu->mb_req_pdu.request_data[data_len];
    }
    /*取得这次数据的LRC验证码*/
    verify = get_lrc_verify_num(verify_array, data_len + 2);
    /*进行校验*/
    if (verify == mb_adu->verifaction_low8) {
        return (VERIFY_SUCCESS);
    } else {
        return (VERIFY_FAIL);
    }
}
/*! \brief ascii模式的正常响应函数
 * \param mb_rsp_pdu 回应主机时,需要响应数据结构
 * \retrun
 */
void ascii_normal_rsp(mb_rsp_pdu_struct *mb_rsp_pdu) {
    uint8 send_normal_adu[ NORMAL_ADU_MAX_LEN ];
    uint8 string_num[ NORMAL_ADU_MAX_LEN * 2 + 1 ];
    uint8 i;
    send_normal_adu[0] = SLAVE_ADDRESS;
    send_normal_adu[1] = mb_rsp_pdu->function_code;
    for (i = 0; i < mb_rsp_pdu->request_data_len; i++) {
        send_normal_adu[2 + i] = mb_rsp_pdu->response_data[i];
    }
    send_normal_adu[2 + i] = get_lrc_verify_num(send_normal_adu, 2 + mb_rsp_pdu->request_data_len);
    /*将回应序列打包成ascii码*/
    num_array2string(send_normal_adu, string_num, 3 + mb_rsp_pdu->request_data_len);
    set_485(TX_485);
    send_byte(':');
    uart_send_string(string_num);
    send_byte('\r');
    send_byte('\n');
    enable_send_byte();
#ifdef __DEBUG__
    debug_send_byte(':');
    debug_uart_send_string(string_num);
    debug_send_byte('\r');
    debug_send_byte('\n');
#endif
}
/*! \brief ascii模式的异常响应函数
 * \param  mb_except_pdu 回应主机时,需要响应数据结构
 * \retrun
 */
void ascii_except_rsp(mb_excep_rsp_pdu_struct *mb_except_pdu) {
    uint8 send_except_adu[ ASCII_EXCEPT_ADU_MAX_LEN ];
    uint8 string_num[ ASCII_EXCEPT_ADU_MAX_LEN * 2 + 1 ];
    send_except_adu[0] = SLAVE_ADDRESS;
    send_except_adu[1] = mb_except_pdu->exception_function_code;
    send_except_adu[2] = mb_except_pdu->exception_code;
    send_except_adu[3] = get_lrc_verify_num(send_except_adu, 3);
    /*打包成ascii码序列*/
    num_array2string(send_except_adu, string_num, ASCII_EXCEPT_ADU_MAX_LEN);
    set_485(TX_485);
    send_byte(':');
    uart_send_string(string_num);
    send_byte('\r');
    send_byte('\n');
    enable_send_byte();
}
/*! \brief 接收帧数据,这个函数放在串口中断中,在接收过程中,会过滤掉开始与结束标识符.
 * \param data 串口数据入口
 * \retrun
 */
void ascii_receive_frame_function(const uint8 data) {
    /*如果接收帧的长度大过能接收的最大程度，则出错，丢弃该帧*/
    if (slave_receiving_counter >= RECEIVE_MAX_LEN) {
#ifdef __DEBUG__
        debug_uart_send_string("over modbus max len.\r\n");
#endif
        slave_receiving_counter = 0;
        return;
    }
    if (slave_receive_frame.receive_frame_done == 0) {
        if (ASCII_START == ascii_receive_status) {
            /* 字符传输间超时，则丢弃该帧**/
            if (IS_TIMEOUT ==  mb_get_frame_char_timeout_status()) {
                ascii_bus_init();
#ifdef __DEBUG__
                debug_uart_send_string("modbus time out.\r\n");
#endif
                mb_frame_char_timeout_clr();
                return;
            }
            /* 如果没超时接收到下一个字符,则重置一下超时设定。**/
            mb_set_frame_char_timeout(SLAVE_DEFAULT_TIMEOUT);
            /* 如果在接收过程中,在接收到开始字符,则认为这个帧错误,重新接收**/
            /* 传输的字符错误的话，也将丢弃该帧*/
            if ((data > ('0' - 1) && data < ('9' + 1)) || (data > ('a' - 1) && data < ('f' + 1)) || (data > ('A' - 1) && data < ('F' + 1)) || data == '\r' || data == '\n') {
                slave_receive_frame.receive_frame[slave_receiving_counter] = data;
            } else {
#ifdef __DEBUG__
                debug_uart_send_string("modbus receives error character.\r\n");
#endif
                ascii_bus_init();
                return;
            }
            /*检查是否接收到结束标识符,两个字符*/
            if (slave_receive_frame.receive_frame[slave_receiving_counter] == '\n' && slave_receive_frame.receive_frame[slave_receiving_counter - 1] == '\r') {
                slave_receive_frame.receive_frame_done = 1;
                slave_receive_frame.frame_len = slave_receiving_counter - 2 + 1;
                ascii_bus_init();
                /*当接收完，就没必要算每个字符的接收间隔了*/
                mb_set_frame_char_timeout(0);
                mb_frame_char_timeout_clr();
                return;
            }
            slave_receiving_counter++;
        }
        /*检查是否开始接收帧数据*/
        if (data == ':') {
            ascii_bus_start_receive();
        }
    }
}
#endif
#endif
